package com.funo.core.base;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;

import com.funo.common.pojo.QueryCondition;

/**
 * Dao基类
 * 
 * @author wx
 * @param <T>
 *            实体泛型
 * @param <PK>
 *            实体主键泛型
 */
public abstract class BaseDao<T, PK extends Serializable> {
	@Autowired
	private SessionFactory sessionFactory;
	private Class<T> entityClass;

	private Session session() {
		return sessionFactory.getCurrentSession();
	}

	public BaseDao() {
		this.entityClass = null;
		Class c = this.getClass();
		Type type = c.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			Type[] parameterizedType = ((ParameterizedType) type)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
		}
	}

	/**
	 * 保存实体
	 * 
	 * @param t
	 */
	public void save(T t) {
		session().save(t);
	}

	/**
	 * 删除实体
	 * 
	 * @param t
	 */
	public void delete(T t) {
		session().delete(t);
	}

	/**
	 * 通过主键删除实体
	 * 
	 * @param id
	 */
	public void delete(PK id) {
		session().delete(this.get(id));
	}

	/**
	 * 更新实体
	 * 
	 * @param t
	 */
	public void update(T t) {
		session().update(t);
	}

	/**
	 * 保存或更新实体
	 * 
	 * @param t
	 */
	public void saveOrUpdate(T t) {
		session().saveOrUpdate(t);
	}

	/**
	 * 根据主键获取实体
	 * 
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T get(PK id) {
		return (T) session().get(this.entityClass, id);
	}

	/**
	 * 根据主键加载实体
	 * 
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T load(PK id) {
		return (T) session().load(this.entityClass, id);
	}

	/**
	 * 获取全部实体
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		return session().createCriteria(this.entityClass).list();
	}

	/**
	 * 获取Criteria
	 * 
	 * @return
	 */
	public Criteria getCriteria() {
		return session().createCriteria(this.entityClass);
	}

	/**
	 * QBC查询
	 * 
	 * @param criteria
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(Criteria criteria) {
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	public Integer countByCriteria(Criteria criteria) {
		Integer total = 0;
		criteria.setProjection(Projections.rowCount());
		List<Object> list = criteria.list();
		if (list != null && list.size() > 0) {
			total = Integer.parseInt(list.get(0).toString());
		}
		return total;
	}

	/**
	 * QBE查询
	 * 
	 * @param t
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByExample(T t) {
		Example example = Example.create(t);
		Criteria criteria = session().createCriteria(this.entityClass);
		criteria.add(example);
		return criteria.list();
	}

	/**
	 * HQL查询
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByHql(final String hql, final Object... params) {
		Query query = session().createQuery(hql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.list();
	}
	
	/**
	 * HQL分页条件查询
	 * @param hql 查询条件+查询参数等
	 * @param condition　分页模型
	 * @return 列表
	 */
	@SuppressWarnings("unchecked")
	public List<T> ListPage(final String hql,final QueryCondition condition){
		Query query = session().createQuery(hql);
		query.setFirstResult(condition.getStart());
		query.setMaxResults(condition.getLimit());
		return query.list();
	}

	/**
	 * 执行HQL
	 * @param hql
	 * @param params
	 * @return
	 */
	public boolean executeHql(final String hql, final Object... params) {
		Query query = session().createQuery(hql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.executeUpdate()>0?true:false;
	}

	/**
	 * SQL查询
	 * 
	 * @param sql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Object[]> findBySql(final String sql, final Object... params) {
		Query query = session().createSQLQuery(sql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params);
		}
		return query.list();
	}
}
